home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- * atmosph.c
- *
- * This module contains all functions for atmospheric effects.
- *
- * from Persistence of Vision(tm) Ray Tracer
- * Copyright 1996 Persistence of Vision Team
- *---------------------------------------------------------------------------
- * NOTICE: This source code file is provided so that users may experiment
- * with enhancements to POV-Ray and to port the software to platforms other
- * than those supported by the POV-Ray Team. There are strict rules under
- * which you are permitted to use this file. The rules are in the file
- * named POVLEGAL.DOC which should be distributed with this file. If
- * POVLEGAL.DOC is not available or for more info please contact the POV-Ray
- * Team Coordinator by leaving a message in CompuServe's Graphics Developer's
- * Forum. The latest version of POV-Ray may be found there as well.
- *
- * This program is based on the popular DKB raytracer version 2.12.
- * DKBTrace was originally written by David K. Buck.
- * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
- *
- *****************************************************************************/
-
- #include "frame.h"
- #include "vector.h"
- #include "povproto.h"
- #include "atmosph.h"
- #include "colour.h"
- #include "povray.h"
- #include "texture.h"
- #include "pigment.h"
- #include "objects.h"
- #include "lighting.h"
- #include "matrices.h"
- #include "texture.h"
-
-
-
- /*****************************************************************************
- * Local preprocessor defines
- ******************************************************************************/
-
- #define BLACK_LEVEL 0.0001
-
-
-
- /*****************************************************************************
- * Local typedefs
- ******************************************************************************/
-
- typedef struct Light_List_Struct LIGHT_LIST;
-
- struct Light_List_Struct
- {
- int active;
- DBL t1, t2;
- LIGHT_SOURCE *Light;
- };
-
-
-
- /*****************************************************************************
- * Local variables
- ******************************************************************************/
-
- /*
- * Atmosphere stuff.
- */
-
- /* List of active lights. */
-
- static LIGHT_LIST *Light_List;
-
- /* Min. and max. intersetcion depths with light source areas. */
-
- static DBL *tmin, *tmax;
-
-
-
- /*****************************************************************************
- * Static functions
- ******************************************************************************/
-
- static DBL constant_fog PARAMS((RAY *Ray, DBL Depth, DBL Width, FOG *Fog, COLOUR Colour));
- static DBL ground_fog PARAMS((RAY *Ray, DBL Depth, DBL Width, FOG *Fog, COLOUR Colour));
-
- static void supersample_atmosphere PARAMS((LIGHT_LIST *Light_List,
- int level, RAY *Ray, ATMOSPHERE *Atmosphere,
- DBL d1, COLOUR C1, DBL d3, COLOUR C3));
-
- static void sample_atmosphere PARAMS((LIGHT_LIST *Light_List, DBL dist,
- RAY *Ray, ATMOSPHERE *Atmosphere, COLOUR Col));
-
- static int intersect_spotlight PARAMS((RAY *Ray, LIGHT_SOURCE *Light, DBL *d1, DBL *d2));
- static int intersect_cylinderlight PARAMS((RAY *Ray, LIGHT_SOURCE *Light, DBL *d1, DBL *d2));
-
- static void do_atmospheric_scattering PARAMS((RAY *Ray, INTERSECTION *Intersection, COLOUR Colour, int Light_Ray_Flag));
- static void do_fog PARAMS((RAY *Ray, INTERSECTION *Intersection, COLOUR Colour, int Light_Ray_Flag));
- static void do_rainbow PARAMS((RAY *Ray, INTERSECTION *Intersection, COLOUR Colour));
- static void do_skysphere PARAMS((RAY *Ray, COLOUR Colour));
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Initialize_Atmosphere_Code
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Initialize atmosphere specific variables.
- *
- * CHANGES
- *
- * Aug 1995 : Creation.
- *
- ******************************************************************************/
-
- void Initialize_Atmosphere_Code()
- {
- Light_List = NULL;
-
- tmin = NULL;
- tmax = NULL;
-
- /* Allocate memory for atmosphere. */
-
- if ((Frame.Atmosphere != NULL) &&
- (fabs(Frame.Atmosphere->Distance) > EPSILON) &&
- (Frame.Number_Of_Light_Sources > 0))
- {
- Light_List = (LIGHT_LIST *)POV_MALLOC(Frame.Number_Of_Light_Sources * sizeof(LIGHT_LIST), "atmosphere sampling lists");
-
- tmin = (DBL *)POV_MALLOC(Frame.Number_Of_Light_Sources * sizeof(DBL), "atmosphere sampling lists");
-
- tmax = (DBL *)POV_MALLOC(Frame.Number_Of_Light_Sources * sizeof(DBL), "atmosphere sampling lists");
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Deinitialize_Atmosphere_Code
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Deinitialize atmosphere specific variables.
- *
- * CHANGES
- *
- * Aug 1995 : Creation.
- *
- ******************************************************************************/
-
- void Deinitialize_Atmosphere_Code()
- {
- /* Free memory used by atmosphere. */
-
- if (Light_List != NULL)
- {
- POV_FREE(Light_List);
- POV_FREE(tmin);
- POV_FREE(tmax);
- }
-
- Light_List = NULL;
-
- tmin = NULL;
- tmax = NULL;
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Do_Infinite_Atmosphere
- *
- * INPUT
- *
- * Ray - Current ray
- *
- * OUTPUT
- *
- * Colour - Color of the current ray
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Apply atmospheric effects to an infinite ray.
- *
- * CHANGES
- *
- * Feb 1995 : Creation.
- *
- * Jun 1995 : Added code for alpha channel support. [DB]
- *
- ******************************************************************************/
-
- void Do_Infinite_Atmosphere(Ray, Colour)
- RAY *Ray;
- COLOUR Colour;
- {
- /* Set background color. */
-
- Assign_Colour(Colour, Frame.Background_Colour);
-
- Colour[FILTER] = 0.0;
- Colour[TRANSM] = 1.0;
-
- /* Determine atmospheric effects for infinite ray. */
-
- do_skysphere(Ray, Colour);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Do_Finite_Atmosphere
- *
- * INPUT
- *
- * Ray - Current ray
- * Intersection - Current intersection
- * Light_Ray_Flag - TRUE if ray is a light source ray
- *
- * OUTPUT
- *
- * Colour - Color of the current ray
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Apply atmospheric effects to a finite ray.
- *
- * CHANGES
- *
- * Feb 1995 : Creation.
- *
- ******************************************************************************/
-
- void Do_Finite_Atmosphere(Ray, Intersection, Colour, Light_Ray_Flag)
- RAY *Ray;
- INTERSECTION *Intersection;
- COLOUR Colour;
- int Light_Ray_Flag;
- {
- if (!Light_Ray_Flag)
- {
- do_rainbow(Ray, Intersection, Colour);
- }
-
- do_atmospheric_scattering(Ray, Intersection, Colour, Light_Ray_Flag);
-
- do_fog(Ray, Intersection, Colour, Light_Ray_Flag);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * do_atmospheric_scattering
- *
- * INPUT
- *
- * Ray - Current ray
- * Intersection - Current intersection
- * Light_Ray_Flag - TRUE if ray is a light source ray
- *
- * OUTPUT
- *
- * Colour - Color of the current ray
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Simulate atmospheric scattering using volume sampling.
- *
- * Ideas for the atmospheric scattering were taken from:
- *
- * - M. Inakage, "An Illumination Model for Atmospheric Environments", ..
- *
- * - Nishita, T., Miyawaki, Y. and Nakamae, E., "A Shading Model for
- * Atmospheric Scattering Considering Luminous Intensity Distribution
- * of Light Sources", Computer Graphics, 21, 4, 1987, 303-310
- *
- * CHANGES
- *
- * Nov 1994 : Creation.
- *
- * Jan 1995 : Added support of cylindrical light sources. [DB]
- *
- * Jun 1995 : Added code for alpha channel support. [DB]
- *
- ******************************************************************************/
-
- static void do_atmospheric_scattering(Ray, Intersection, Colour, Light_Ray_Flag)
- RAY *Ray;
- INTERSECTION *Intersection;
- COLOUR Colour;
- int Light_Ray_Flag;
- {
- int i, j;
- int active, interval, intervals, insert;
- DBL k, jdist, t1, t2, f, fi;
- DBL dist, dist_prev;
- DBL step;
- COLOUR Col_total, Col, Col_prev, Max_Colour, C1, C2;
- LIGHT_SOURCE *Light;
- ATMOSPHERE *Atmosphere;
-
- /* Why are we here? */
-
- if (((Atmosphere = Frame.Atmosphere) == NULL) ||
- (Frame.Atmosphere->Distance == 0.0) ||
- (Frame.Number_Of_Light_Sources == 0))
- {
- return;
- }
-
- /*
- * If we have a light source ray we only have to attenuate
- * the light source color due to the distance traveled.
- */
-
- if (Light_Ray_Flag)
- {
- k = exp(-Intersection->Depth / Atmosphere->Distance);
-
- /* Check for minimum transmittance. */
-
- if (k < Atmosphere->Colour[TRANSM])
- {
- k = Atmosphere->Colour[TRANSM];
- }
-
- VScaleEq(Colour, k);
-
- return;
- }
-
- /* Init light list and sampling intervals. */
-
- for (i = 0; i < Frame.Number_Of_Light_Sources; i++)
- {
- Light_List[i].active = FALSE;
- Light_List[i].t1 = 0.0;
- Light_List[i].t2 = Max_Distance;
- Light_List[i].Light = NULL;
-
- tmin[i] = BOUND_HUGE;
- tmax[i] = -BOUND_HUGE;
- }
-
- /* Get depths for all light sources and disconnected sampling intervals. */
-
- active = 0;
-
- intervals = 0;
-
- t1 = t2 = 0.0;
-
- Make_Colour(Max_Colour, 0.0, 0.0, 0.0);
-
- for (i = 0, Light = Frame.Light_Sources; Light != NULL; Light = Light->Next_Light_Source, i++)
- {
- insert = FALSE;
-
- Light_List[i].Light = Light;
-
- if (!Light->Atmosphere_Interaction)
- {
- continue;
- }
-
- switch (Light->Light_Type)
- {
- case CYLINDER_SOURCE:
-
- if (intersect_cylinderlight(Ray, Light, &t1, &t2))
- {
- if ((t1 < Intersection->Depth) && (t2 > Small_Tolerance))
- {
- insert = TRUE;
- }
- }
-
- break;
-
- case POINT_SOURCE:
-
- t1 = 0.0;
- t2 = Intersection->Depth;
-
- insert = TRUE;
-
- break;
-
- case SPOT_SOURCE:
-
- if (intersect_spotlight(Ray, Light, &t1, &t2))
- {
- if ((t1 < Intersection->Depth) && (t2 > Small_Tolerance))
- {
- insert = TRUE;
- }
- }
-
- break;
- }
-
- /* Insert distances into sampling interval list. */
-
- if (insert)
- {
- /* Add light color to maximum color. */
-
- VAddEq(Max_Colour, Light->Colour);
-
- /* Number of active light sources. */
-
- active ++;
-
- /* Insert light source intersections into light list. */
-
- t1 = max(t1, 0.0);
- t2 = min(t2, Intersection->Depth);
-
- Light_List[i].active = TRUE;
- Light_List[i].t1 = t1;
- Light_List[i].t2 = t2;
-
- /* Test if there's an overlapping interval. */
-
- for (j = 0; j < intervals; j++)
- {
- if (!((t2 < tmin[j]) || (t1 > tmax[j])))
- {
- /* The intervals are overlapping. */
-
- break;
- }
- }
-
- if (j >= intervals)
- {
- j = intervals;
-
- intervals++;
- }
-
- /* Adjust interval. */
-
- tmin[j] = min(tmin[j], t1);
- tmax[j] = max(tmax[j], t2);
- }
- }
-
- /* Initialize maximum color. */
-
- Max_Colour[RED] = (Max_Colour[RED] > EPSILON) ? 1.0 : 0.0;
- Max_Colour[GREEN] = (Max_Colour[GREEN] > EPSILON) ? 1.0 : 0.0;
- Max_Colour[BLUE] = (Max_Colour[BLUE] > EPSILON) ? 1.0 : 0.0;
-
- /*
- * If there are no active lights, we can skip ahead because no
- * light from any light source will reach the viewer.
- */
-
- Make_Colour(Col_total, 0.0, 0.0, 0.0);
-
- if (active > 0)
- {
- for (interval = 0; interval < intervals; interval++)
- {
- /* Get sampling step distance. */
-
- step = min((tmax[interval] - tmin[interval]), Atmosphere->Distance) / (DBL)Atmosphere->Samples;
-
- /* Set up distance. */
-
- dist = dist_prev = 0.0;
-
- /* Sample along the ray. */
-
- Make_Colour(Col, 0.0, 0.0, 0.0);
-
- for (i = 0; dist < tmax[interval]; i++)
- {
- /* Step to next sample point. */
-
- dist = tmin[interval] + ((DBL)i + 0.5) * step;
-
- /* Get distance of current sampling point. */
-
- jdist = dist + Atmosphere->Jitter * step * (FRAND() - 0.5);
-
- /* If we're behind the intersection point we can quit. */
-
- if (jdist >= Intersection->Depth)
- {
- break;
- }
-
- sample_atmosphere(Light_List, jdist, Ray, Atmosphere, Col);
-
- /* Add previous result to the total color. */
-
- if (i)
- {
- /* Do the current and previous colours differ too much? */
-
- if ((Atmosphere->AA_Level > 0) && (Colour_Distance(Col, Col_prev) >= Atmosphere->AA_Threshold))
- {
- /* Supersample between current and previous point. */
-
- supersample_atmosphere(Light_List, 1, Ray, Atmosphere, dist_prev, Col_prev, dist, Col);
-
- Col[RED] = Col_prev[RED] = 0.5 * (Col[RED] + Col_prev[RED]);
- Col[GREEN] = Col_prev[GREEN] = 0.5 * (Col[GREEN] + Col_prev[GREEN]);
- Col[BLUE] = Col_prev[BLUE] = 0.5 * (Col[BLUE] + Col_prev[BLUE]);
- }
-
- /* Get attenuation due to distance from view point. */
-
- k = step * exp(-dist_prev / Atmosphere->Distance);
-
- /* If the contribution is too small we can stop. */
-
- if (k < BLACK_LEVEL)
- {
- break;
- }
-
- Col_total[RED] += k * Col_prev[RED];
- Col_total[GREEN] += k * Col_prev[GREEN];
- Col_total[BLUE] += k * Col_prev[BLUE];
-
- /* If the total color is larger than max. value we can stop now. */
-
- if ((Col_total[RED] >= Max_Colour[RED]) &&
- (Col_total[GREEN] >= Max_Colour[GREEN]) &&
- (Col_total[BLUE] >= Max_Colour[BLUE]))
- {
- break;
- }
- }
-
- dist_prev = dist;
-
- Assign_Colour(Col_prev, Col);
- }
-
- /* Add last result to the total color. */
-
- /* Get attenuation due to distance from view point. */
-
- k = step * exp(-dist / Atmosphere->Distance);
-
- Col_total[RED] += k * Col_prev[RED];
- Col_total[GREEN] += k * Col_prev[GREEN];
- Col_total[BLUE] += k * Col_prev[BLUE];
-
- /* If the total color is white already we can stop now. */
-
- if ((Col_total[RED] >= 1.0) && (Col_total[GREEN] >= 1.0) && (Col_total[BLUE] >= 1.0))
- {
- break;
- }
- }
- }
-
- /* Add attenuated background color. */
-
- k = exp(-Intersection->Depth / Atmosphere->Distance);
-
- /* Check for minimum transmittance. */
-
- if (k < Atmosphere->Colour[TRANSM])
- {
- k = Atmosphere->Colour[TRANSM];
- }
-
- /*
- ki = 1.0 - k;
-
- VLinComb3(Colour, 1.0, Col_total, k, Colour, ki, Atmosphere->Colour);
- */
-
- /* Attenuate color due to atmosphere color. */
-
- f = Atmosphere->Colour[FILTER];
-
- fi = 1.0 - f;
-
- C1[RED] = Col_total[RED] * (fi + f * Atmosphere->Colour[RED]);
- C1[GREEN] = Col_total[GREEN] * (fi + f * Atmosphere->Colour[GREEN]);
- C1[BLUE] = Col_total[BLUE] * (fi + f * Atmosphere->Colour[BLUE]);
-
- C2[RED] = Colour[RED] * (fi + f * Atmosphere->Colour[RED]);
- C2[GREEN] = Colour[GREEN] * (fi + f * Atmosphere->Colour[GREEN]);
- C2[BLUE] = Colour[BLUE] * (fi + f * Atmosphere->Colour[BLUE]);
-
- VLinComb2(Colour, 1.0, C1, k, C2);
-
- Colour[FILTER] = k * Colour[FILTER];
- Colour[TRANSM] = k * Colour[TRANSM];
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * supersample_atmosphere
- *
- * INPUT
- *
- * Light_List - array containing light source information
- * level - level of recursion
- * Ray - pointer to ray
- * Atmosphere - pointer to atmosphere to use
- * d1 - distance to lower sample
- * d3 - distance to upper sample
- *
- * OUTPUT
- *
- * C1 - Color of lower sample
- * C3 - Color of upper sample
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Recursevily supersample between two points on the ray.
- *
- * CHANGES
- *
- * Nov 1994 : Creation.
- *
- ******************************************************************************/
-
- static void supersample_atmosphere(Light_List, level, Ray, Atmosphere, d1, C1, d3, C3)
- LIGHT_LIST *Light_List;
- int level;
- RAY *Ray;
- ATMOSPHERE *Atmosphere;
- DBL d1, d3;
- COLOUR C1, C3;
- {
- DBL d2, jdist;
- COLOUR C2;
-
- Increase_Counter(stats[Atmosphere_Supersamples]);
-
- /* Sample between lower and upper point. */
-
- d2 = 0.5 * (d1 + d3);
-
- jdist = d2 + Atmosphere->Jitter * 0.5 * (d3 - d1) * (FRAND() - 0.5);
-
- sample_atmosphere(Light_List, jdist, Ray, Atmosphere, C2);
-
- /* Test for further supersampling. */
-
- if (level < Atmosphere->AA_Level)
- {
- if (Colour_Distance(C1, C2) >= Atmosphere->AA_Threshold)
- {
- /* Supersample between lower and middle point. */
-
- supersample_atmosphere(Light_List, level+1, Ray, Atmosphere, d1, C1, d2, C2);
- }
-
- if (Colour_Distance(C2, C3) >= Atmosphere->AA_Threshold)
- {
- /* Supersample between current and higher point. */
-
- supersample_atmosphere(Light_List, level+1, Ray, Atmosphere, d2, C2, d3, C3);
- }
- }
-
- /* Add supersampled colors. */
-
- VLinComb2(C1, 0.75, C1, 0.25, C2);
- VLinComb2(C3, 0.25, C2, 0.75, C3);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * sample_atmosphere
- *
- * INPUT
- *
- * Light_List - array containing light source information
- * dist - distance of current sample
- * Ray - pointer to ray
- * Atmosphere - pointer to atmosphere to use
- *
- * OUTPUT
- *
- * Col - color of current sample
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Calculate the color of the current atmosphere sample, i.e. the
- * sample at distance dist, by summing the light reaching that point
- * from all light sources.
- *
- * CHANGES
- *
- * Nov 1994 : Creation.
- *
- ******************************************************************************/
-
- static void sample_atmosphere(Light_List, dist, Ray, Atmosphere, Col)
- LIGHT_LIST *Light_List;
- DBL dist;
- RAY *Ray;
- ATMOSPHERE *Atmosphere;
- COLOUR Col;
- {
- int i;
- DBL alpha, len, k, g, g2;
- VECTOR P;
- COLOUR Light_Colour;
- RAY Light_Ray;
-
- Increase_Counter(stats[Atmosphere_Samples]);
-
- /* Get current sample point. */
-
- VEvaluateRay(P, Ray->Initial, dist, Ray->Direction);
-
- /* Process all light sources. */
-
- Make_Colour(Col, 0.0, 0.0, 0.0);
-
- for (i = 0; i < Frame.Number_Of_Light_Sources; i++)
- {
- /* Use light only if active and within it's boundaries. */
-
- if (Light_List[i].active && (dist >= Light_List[i].t1) && (dist <= Light_List[i].t2))
- {
- if (!(Test_Shadow(Light_List[i].Light, &len, &Light_Ray, Ray, P, Light_Colour)))
- {
- VDot(alpha, Light_Ray.Direction, Ray->Direction);
-
- /* Get attenuation due to scattering. */
-
- switch (Atmosphere->Type)
- {
- case RAYLEIGH_SCATTERING:
-
- k = (1.0 + Sqr(alpha)) / 2.0;
-
- break;
-
- case MIE_HAZY_SCATTERING:
-
- k = 0.1 * (1.0 + 0.03515625 * pow(1.0 + alpha, 8.0));
-
- break;
-
- case MIE_MURKY_SCATTERING:
-
- k = 0.019607843 * (1.0 + 1.1641532e-8 * pow(1.0 + alpha, 32.0));
-
- break;
-
- case HENYEY_GREENSTEIN_SCATTERING:
-
- g = Atmosphere->Eccentricity;
-
- g2 = Sqr(g);
-
- k = (1.0 - g2) / pow(1.0 + g2 - 2.0 * g * alpha, 1.5);
-
- break;
-
- case ISOTROPIC_SCATTERING:
- default:
-
- k = 1.0;
-
- break;
- }
-
- k *= Atmosphere->Scattering;
-
- VAddScaledEq(Col, k, Light_Colour);
- }
- }
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * do_fog
- *
- * INPUT
- *
- * Ray - current ray
- * Intersection - current intersection
- * Light_Ray_Flag - TRUE if ray is a light source ray
- *
- * OUTPUT
- *
- * Colour - color of current ray
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * Evaluate all fogs for the current ray and intersection.
- *
- * CHANGES
- *
- * Dec 1994 : Rewritten to allow multiple fogs. [DB]
- *
- * Apr 1995 : Added transmittance threshold and filtering. [DB]
- *
- * Jun 1995 : Added code for alpha channel support. [DB]
- *
- ******************************************************************************/
-
- static void do_fog(Ray, Intersection, Colour, Light_Ray_Flag)
- RAY *Ray;
- INTERSECTION *Intersection;
- COLOUR Colour;
- int Light_Ray_Flag;
- {
- DBL att, att_inv, width;
- COLOUR Col_Fog;
- COLOUR sum_att; /* total attenuation. */
- COLOUR sum_col; /* total color. */
- FOG *Fog;
-
- /* Why are we here. */
-
- if (Frame.Fog == NULL)
- {
- return;
- }
-
- /* Init total attenuation and total color. */
-
- Make_ColourA(sum_att, 1.0, 1.0, 1.0, 1.0, 1.0);
- Make_ColourA(sum_col, 0.0, 0.0, 0.0, 0.0, 0.0);
-
- /* Loop over all fogs. */
-
- for (Fog = Frame.Fog; Fog != NULL; Fog = Fog->Next)
- {
- /* Don't care about fogs with zero distance. */
-
- if (fabs(Fog->Distance) > EPSILON)
- {
- width = Intersection->Depth;
-
- switch (Fog->Type)
- {
- case GROUND_MIST:
-
- att = ground_fog(Ray, 0.0, width, Fog, Col_Fog);
-
- break;
-
- default:
-
- att = constant_fog(Ray, 0.0, width, Fog, Col_Fog);
-
- break;
- }
-
- /* Check for minimum transmittance. */
-
- if (att < Col_Fog[TRANSM])
- {
- att = Col_Fog[TRANSM];
- }
-
- /* Get attenuation sum due to filtered/unfiltered translucency. */
-
- sum_att[RED] *= att * ((1.0 - Col_Fog[FILTER]) + Col_Fog[FILTER] * Col_Fog[RED]);
- sum_att[GREEN] *= att * ((1.0 - Col_Fog[FILTER]) + Col_Fog[FILTER] * Col_Fog[GREEN]);
- sum_att[BLUE] *= att * ((1.0 - Col_Fog[FILTER]) + Col_Fog[FILTER] * Col_Fog[BLUE]);
- sum_att[FILTER] *= att * Col_Fog[FILTER];
- sum_att[TRANSM] *= att * Col_Fog[TRANSM];
-
- if (!Light_Ray_Flag)
- {
- att_inv = 1.0 - att;
-
- VAddScaledEq(sum_col, att_inv, Col_Fog);
- }
- }
- }
-
- /* Add light coming from background. */
-
- sum_col[RED] += sum_att[RED] * Colour[RED];
- sum_col[GREEN] += sum_att[GREEN] * Colour[GREEN];
- sum_col[BLUE] += sum_att[BLUE] * Colour[BLUE];
- sum_col[FILTER] += sum_att[FILTER] * Colour[FILTER];
- sum_col[TRANSM] += sum_att[TRANSM] * Colour[TRANSM];
-
- Assign_Colour(Colour, sum_col);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * do_rainbow
- *
- * INPUT
- *
- * Ray - Current ray
- * Intersection - Cuurent intersection
- *
- * OUTPUT
- *
- * Colour - Current colour
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Create a rainbow using an impressionistic model.
- *
- * The model was taken from:
- *
- * Musgrave, F. Kenton, "Prisms and Rainbows: a Dispersion Model
- * for Computer Graphics", Proceedings of Graphics Interface '89 -
- * Vision Interface '89, p. 227-234.
- *
- * CHANGES
- *
- * Jul 1994 : Creation.
- *
- * Dec 1994 : Modified to allow multiple rainbows. [DB]
- *
- * Apr 1995 : Added rainbow arcs and filtering. [DB]
- *
- * Jun 1995 : Added code for alpha channel support. [DB]
- *
- ******************************************************************************/
-
- static void do_rainbow(Ray, Intersection, Colour)
- RAY *Ray;
- INTERSECTION *Intersection;
- COLOUR Colour;
- {
- int n;
- DBL dot, k, ki, index, x, y, l, angle, fade, f;
- VECTOR Temp;
- COLOUR Cr, Ct;
- RAINBOW *Rainbow;
-
- /* Why are we here. */
-
- if (Frame.Rainbow == NULL)
- {
- return;
- }
-
- Make_ColourA(Ct, 0.0, 0.0, 0.0, 1.0, 1.0);
-
- n = 0;
-
- for (Rainbow = Frame.Rainbow; Rainbow != NULL; Rainbow = Rainbow->Next)
- {
- if ((Rainbow->Pigment != NULL) && (Rainbow->Distance != 0.0) && (Rainbow->Width != 0.0))
- {
- /* Get angle between ray direction and rainbow's up vector. */
-
- VDot(x, Ray->Direction, Rainbow->Right_Vector);
- VDot(y, Ray->Direction, Rainbow->Up_Vector);
-
- l = Sqr(x) + Sqr(y);
-
- if (l > 0.0)
- {
- l = sqrt(l);
-
- y /= l;
- }
-
- angle = fabs(acos(y));
-
- if (angle <= Rainbow->Arc_Angle)
- {
- /* Get dot product between ray direction and antisolar vector. */
-
- VDot(dot, Ray->Direction, Rainbow->Antisolar_Vector);
-
- if (dot >= 0.0)
- {
- /* Get index ([0;1]) into rainbow's colour map. */
-
- index = (acos(dot) - Rainbow->Angle) / Rainbow->Width;
-
- /* Jitter index. */
-
- if (Rainbow->Jitter > 0.0)
- {
- index += (2.0 * FRAND() - 1.0) * Rainbow->Jitter;
- }
-
- if ((index >= 0.0) && (index <= 1.0 - EPSILON))
- {
- /* Get colour from rainbow's colour map. */
-
- Make_Vector(Temp, index, 0.0, 0.0);
-
- Compute_Pigment(Cr, Rainbow->Pigment, Temp);
-
- /* Get fading value for falloff. */
-
- if ((Rainbow->Falloff_Width > 0.0) && (angle > Rainbow->Falloff_Angle))
- {
- fade = (angle - Rainbow->Falloff_Angle) / Rainbow->Falloff_Width;
-
- fade = (3.0 - 2.0 * fade) * fade * fade;
- }
- else
- {
- fade = 0.0;
- }
-
- /* Get attenuation factor due to distance. */
-
- k = exp(-Intersection->Depth / Rainbow->Distance);
-
- /* Colour's transm value is used as minimum attenuation value. */
-
- k = max(k, fade * (1.0 - Cr[TRANSM]) + Cr[TRANSM]);
-
- /* Now interpolate the colours. */
-
- ki = 1.0 - k;
-
- /* Attenuate filter value. */
-
- f = Cr[FILTER] * ki;
-
- Ct[RED] += k * Colour[RED] * ((1.0 - f) + f * Cr[RED]) + ki * Cr[RED];
- Ct[GREEN] += k * Colour[GREEN] * ((1.0 - f) + f * Cr[GREEN]) + ki * Cr[GREEN];
- Ct[BLUE] += k * Colour[BLUE] * ((1.0 - f) + f * Cr[BLUE]) + ki * Cr[BLUE];
- Ct[FILTER] *= k * Cr[FILTER];
- Ct[TRANSM] *= k * Cr[TRANSM];
-
- n++;
- }
- }
- }
- }
- }
-
- if (n > 0)
- {
- VInverseScale(Colour, Ct, (DBL)n);
-
- Colour[FILTER] *= Ct[FILTER];
- Colour[TRANSM] *= Ct[TRANSM];
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * do_skysphere
- *
- * INPUT
- *
- * Ray - Current ray
- *
- * OUTPUT
- *
- * Colour - Current color
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Calculate color of the sky.
- *
- * Use the ray direction as a point on the skysphere. Thus the sky can
- * easily be colored with all kinds of pigments.
- *
- * CHANGES
- *
- * Jul 1994 : Creation.
- *
- * Dec 1994 : Modified to allow layered pigments. [DB]
- *
- * Jun 1995 : Added code for alpha channel support. [DB]
- *
- ******************************************************************************/
-
- static void do_skysphere(Ray, Colour)
- RAY *Ray;
- COLOUR Colour;
- {
- int i;
- DBL att, trans;
- COLOUR Col, Col_Temp, Filter;
- VECTOR P;
- SKYSPHERE *Skysphere;
-
- /* Why are we here. */
-
- if (Frame.Skysphere == NULL)
- {
- return;
- }
-
- Make_ColourA(Col, 0.0, 0.0, 0.0, 0.0, 0.0);
-
- if (((Skysphere = Frame.Skysphere) != NULL) && (Skysphere->Pigments != NULL))
- {
- Make_ColourA(Filter, 1.0, 1.0, 1.0, 1.0, 1.0);
-
- trans = 1.0;
-
- /* Transform point on unit sphere. */
-
- if (Skysphere->Trans != NULL)
- {
- MInvTransPoint(P, Ray->Direction, Skysphere->Trans);
- }
- else
- {
- Assign_Vector(P, Ray->Direction);
- }
-
- for (i = Skysphere->Count-1; i >= 0; i--)
- {
- /* Compute sky colour from colour map. */
-
- Compute_Pigment(Col_Temp, Skysphere->Pigments[i], P);
-
- att = trans * (1.0 - Col_Temp[FILTER] - Col_Temp[TRANSM]);
-
- VAddScaledEq(Col, att, Col_Temp);
-
- Filter[RED] *= Col_Temp[RED];
- Filter[GREEN] *= Col_Temp[GREEN];
- Filter[BLUE] *= Col_Temp[BLUE];
- Filter[FILTER] *= Col_Temp[FILTER];
- Filter[TRANSM] *= Col_Temp[TRANSM];
-
- trans = fabs(Filter[FILTER]) + fabs(Filter[TRANSM]);
- }
-
- Colour[RED] = Col[RED] + Colour[RED] * (Filter[RED] * Filter[FILTER] + Filter[TRANSM]);
- Colour[GREEN] = Col[GREEN] + Colour[GREEN] * (Filter[GREEN] * Filter[FILTER] + Filter[TRANSM]);
- Colour[BLUE] = Col[BLUE] + Colour[BLUE] * (Filter[BLUE] * Filter[FILTER] + Filter[TRANSM]);
- Colour[FILTER] = Colour[FILTER] * Filter[FILTER];
- Colour[TRANSM] = Colour[TRANSM] * Filter[TRANSM];
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * constant_fog
- *
- * INPUT
- *
- * Ray - current ray
- * Depth - intersection depth with fog's boundary
- * Width - width of the fog along the ray
- * Fog - current fog
- *
- * OUTPUT
- *
- * Colour - color of the fog
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * Apply distance attenuated fog.
- *
- * CHANGES
- *
- * Dec 1994 : Modified to work with multiple fogs. [DB]
- *
- ******************************************************************************/
-
- static DBL constant_fog(Ray, Depth, Width, Fog, Colour)
- RAY *Ray;
- DBL Depth, Width;
- FOG *Fog;
- COLOUR Colour;
- {
- DBL k;
- VECTOR P;
-
- if (Fog->Turb != NULL)
- {
-
- Depth += Width / 2.0;
-
- VEvaluateRay(P, Ray->Initial, Depth, Ray->Direction);
-
- VEvaluateEq(P, Fog->Turb->Turbulence);
-
- /* The further away the less influence turbulence has. */
-
- k = exp(-Width / Fog->Distance);
-
- Width *= 1.0 - k * min(1.0, Turbulence(P, Fog->Turb)*Fog->Turb_Depth);
- }
-
- Assign_Colour(Colour, Fog->Colour);
-
- return (exp(-Width / Fog->Distance));
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * ground_fog
- *
- * INPUT
- *
- * Ray - current ray
- * Depth - intersection depth with fog's boundary
- * Width - width of the fog along the ray
- * Fog - current fog
- *
- * OUTPUT
- *
- * Colour - color of the fog
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Eric Barish
- *
- * DESCRIPTION
- *
- * Here is an ascii graph of the ground fog density, it has a maximum
- * density of 1.0 at Y <= 0, and approaches 0.0 as Y goes up:
- *
- * ***********************************
- * | | | ****
- * | | | ***
- * | | | ***
- * | | | | ****
- * | | | | *****
- * | | | | *******
- * -----+-----------+------------+------------+-----------+-----
- * Y=-2 Y=-1 Y=0 Y=1 Y=2
- *
- * ground fog density is 1 / (Y*Y+1) for Y >= 0 and equals 1.0 for Y <= 0.
- * (It behaves like regular fog for Y <= 0.)
- *
- * The integral of the density is atan(Y) (for Y >= 0).
- *
- * CHANGES
- *
- * Feb 1996 : Changed to behave like normal fog for Y <= 0.
- * Fixed bug with reversed offset effect. [DB]
- *
- ******************************************************************************/
-
- static DBL ground_fog(Ray, Depth, Width, Fog, Colour)
- RAY *Ray;
- DBL Depth, Width;
- FOG *Fog;
- COLOUR Colour;
- {
- DBL fog_density, delta;
- DBL start, end;
- DBL y1, y2, k;
- DBL rdiv;
- VECTOR P, P1, P2;
-
- /* Get start point. */
-
- VEvaluateRay(P1, Ray->Initial, Depth, Ray->Direction);
-
- /* Get end point. */
-
- VLinComb2(P2, 1.0, P1, Width, Ray->Direction);
-
- /*
- * Could preform transfomation here to translate Start and End
- * points into ground fog space.
- */
-
- VDot(y1, P1, Fog->Up);
- VDot(y2, P2, Fog->Up);
-
- rdiv = (1.0 / Fog->Alt);
- start = (y1 - Fog->Offset) * rdiv;
- end = (y2 - Fog->Offset) * rdiv;
-
- /*
- start = (y1 - Fog->Offset) / Fog->Alt;
- end = (y2 - Fog->Offset) / Fog->Alt;
- */
-
- /* Get integral along y-axis from start to end. */
-
- if (start <= 0.0)
- {
- if (end <= 0.0)
- {
- fog_density = 1.0;
- }
- else
- {
- fog_density = (atan(end) - start) / (end - start);
- }
- }
- else
- {
- if (end <= 0.0)
- {
- fog_density = (atan(start) - end) / (start - end);
- }
- else
- {
- delta = start - end;
-
- if (fabs(delta) > EPSILON)
- {
- fog_density = (atan(start) - atan(end)) / delta;
- }
- else
- {
- fog_density = 1.0 / (Sqr(start) + 1.0);
- }
- }
- }
-
- /* Apply turbulence. */
-
- if (Fog->Turb != NULL)
- {
- VHalf(P, P1, P2);
-
- VEvaluateEq(P, Fog->Turb->Turbulence);
-
- /* The further away the less influence turbulence has. */
-
- k = exp(-Width / Fog->Distance);
-
- Width *= 1.0 - k * min(1.0, Turbulence(P, Fog->Turb)*Fog->Turb_Depth);
- }
-
- Assign_Colour(Colour, Fog->Colour);
-
- return (exp(-Width * fog_density / Fog->Distance));
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * intersect_spotlight
- *
- * INPUT
- *
- * Ray - current ray
- * Light - current light source
- *
- * OUTPUT
- *
- * d1, d2 - intersection depths
- *
- * RETURNS
- *
- * int - TRUE, if hit
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Intersect a ray with the light cone of a spotlight.
- *
- * CHANGES
- *
- * Nov 1994 : Creation.
- *
- ******************************************************************************/
-
- static int intersect_spotlight(Ray, Light, d1, d2)
- RAY *Ray;
- LIGHT_SOURCE *Light;
- DBL *d1, *d2;
- {
- int viewpoint_is_in_cone;
- DBL a, b, c, d, m, l, l1, l2, t, t1, t2, k1, k2, k3, k4;
- DBL rdiv;
- VECTOR V1;
-
- /* Get cone's slope. Note that cos(falloff) is stored in Falloff! */
-
- a = acos(Light->Falloff);
-
- /* This only works for a < 180 degrees! */
-
- m = tan(a);
-
- m = 1.0 + Sqr(m);
-
- VSub(V1, Ray->Initial, Light->Center);
-
- VDot(k1, Ray->Direction, Light->Direction);
-
- VDot(k2, V1, Light->Direction);
-
- VLength(l, V1);
-
- if (l > EPSILON)
- {
- viewpoint_is_in_cone = (k2 / l >= Light->Falloff);
- }
- else
- {
- viewpoint_is_in_cone = FALSE;
- }
-
- if ((k1 <= 0.0) && (k2 < 0.0))
- {
- return (FALSE);
- }
-
- VDot(k3, V1, Ray->Direction);
-
- VDot(k4, V1, V1);
-
- a = 1.0 - Sqr(k1) * m;
-
- b = k3 - k1 * k2 * m;
-
- c = k4 - Sqr(k2) * m;
-
- if (a != 0.0)
- {
- d = Sqr(b) - a * c;
-
- if (d > EPSILON)
- {
- d = sqrt(d);
-
- /*
- t1 = (-b + d) / a;
- t2 = (-b - d) / a;
- */
- rdiv = (1.0 / a);
- t1 = (-b + d) * rdiv;
- t2 = (-b - d) * rdiv;
-
- if (t1 > t2)
- {
- t = t1; t1 = t2; t2 = t;
- }
-
- l1 = k2 + t1 * k1;
- l2 = k2 + t2 * k1;
-
- if ((l1 <= 0.0) && (l2 <= 0.0))
- {
- return (FALSE);
- }
-
- if ((l1 <= 0.0) || (l2 <= 0.0))
- {
- if (l1 <= 0.0)
- {
- if (viewpoint_is_in_cone)
- {
- t1 = 0.0;
- t2 = (t2 > 0.0) ? (t2) : (Max_Distance);
- }
- else
- {
- t1 = t2;
- t2 = Max_Distance;
- }
- }
- else
- {
- if (viewpoint_is_in_cone)
- {
- t2 = t1;
- t1 = 0.0;
- }
- else
- {
- t2 = Max_Distance;
- }
- }
- }
-
- *d1 = t1;
- *d2 = t2;
-
- return (TRUE);
- }
- else
- {
- if (d > -EPSILON)
- {
- if (viewpoint_is_in_cone)
- {
- *d1 = 0.0;
- *d2 = -b / a;
- }
- else
- {
- *d1 = -b / a;
- *d2 = Max_Distance;
- }
-
- return(TRUE);
- }
- }
- }
- else
- {
- if (viewpoint_is_in_cone)
- {
- *d1 = 0.0;
- *d2 = -c/b;
-
- return(TRUE);
- }
- }
-
- return (FALSE);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * intersect_cylinderlight
- *
- * INPUT
- *
- * Ray - current ray
- * Light - current light source
- *
- * OUTPUT
- *
- * d1, d2 - intersection depths
- *
- * RETURNS
- *
- * int - TRUE, if hit
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Intersect a ray with the light cylinder of a cylinderlight.
- *
- * CHANGES
- *
- * Jan 1995 : Creation.
- *
- ******************************************************************************/
-
- static int intersect_cylinderlight(Ray, Light, d1, d2)
- RAY *Ray;
- LIGHT_SOURCE *Light;
- DBL *d1, *d2;
- {
- DBL a, b, c, d, l1, l2, t, t1, t2, k1, k2, k3, k4;
- DBL rdiv;
- VECTOR V1;
-
- VSub(V1, Ray->Initial, Light->Center);
-
- VDot(k1, Ray->Direction, Light->Direction);
-
- VDot(k2, V1, Light->Direction);
-
- if ((k1 <= 0.0) && (k2 < 0.0))
- {
- return (FALSE);
- }
-
- a = 1.0 - Sqr(k1);
-
- if (a != 0.0)
- {
- VDot(k3, V1, Ray->Direction);
-
- VDot(k4, V1, V1);
-
- b = k3 - k1 * k2;
-
- c = k4 - Sqr(k2) - Sqr(Light->Falloff);
-
- d = Sqr(b) - a * c;
-
- if (d > EPSILON)
- {
- d = sqrt(d);
-
- rdiv = (1.0 / a);
- t1 = (-b + d) * rdiv;
- t2 = (-b - d) * rdiv;
- /*
- t1 = (-b + d) / a;
- t2 = (-b - d) / a;
- */
- if (t1 > t2)
- {
- t = t1; t1 = t2; t2 = t;
- }
-
- l1 = k2 + t1 * k1;
- l2 = k2 + t2 * k1;
-
- if ((l1 <= 0.0) && (l2 <= 0.0))
- {
- return (FALSE);
- }
-
- if ((l1 <= 0.0) || (l2 <= 0.0))
- {
- if (l1 <= 0.0)
- {
- t1 = 0.0;
- }
- else
- {
- t2 = (Max_Distance - k2) / k1;
- }
- }
-
- *d1 = t1;
- *d2 = t2;
-
- return (TRUE);
- }
- }
-
- return (FALSE);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Create_Atmosphere
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * ATMOSPHERE * - created atmosphere
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Create an atmosphere.
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- ATMOSPHERE *Create_Atmosphere()
- {
- ATMOSPHERE *New;
-
- New = (ATMOSPHERE *)POV_MALLOC(sizeof(ATMOSPHERE), "fog");
-
- New->Type = ISOTROPIC_SCATTERING;
-
- New->Samples = 100;
- New->Distance = 0.0;
- New->Distance_Threshold = 0.005;
- New->Scattering = 1.0;
- New->Eccentricity = 0.0;
-
- Make_Colour(New->Colour, 0.0, 0.0, 0.0);
-
- New->AA_Level = 0;
- New->AA_Threshold = 0.3;
- New->Jitter = 0.0;
-
- return (New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Copy_Atmosphere
- *
- * INPUT
- *
- * Old - atmosphere to copy
- *
- * OUTPUT
- *
- * RETURNS
- *
- * ATMOSPHERE * - new atmosphere
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Copy an atmosphere.
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- void *Copy_Atmosphere(Old)
- ATMOSPHERE *Old;
- {
- ATMOSPHERE *New;
-
- New = Create_Atmosphere();
-
- *New = *Old;
-
- return (New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Destroy_Atmosphere
- *
- * INPUT
- *
- * Atmosphere - atmosphere to destroy
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Destroy an atmosphere.
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- void Destroy_Atmosphere(Atmosphere)
- ATMOSPHERE *Atmosphere;
- {
- if (Atmosphere != NULL)
- {
- POV_FREE(Atmosphere);
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Create_Fog
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * FOG * - created fog
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Create a fog.
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- FOG *Create_Fog()
- {
- FOG *New;
-
- New = (FOG *)POV_MALLOC(sizeof(FOG), "fog");
-
- New->Type = ORIG_FOG;
-
- New->Distance = 0.0;
- New->Alt = 0.0;
- New->Offset = 0.0;
-
- Make_ColourA(New->Colour, 0.0, 0.0, 0.0, 0.0, 0.0);
-
- Make_Vector(New->Up, 0.0, 1.0, 0.0);
-
- New->Turb = NULL;
- New->Turb_Depth = 0.5;
-
- New->Next = NULL;
-
- return (New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Copy_Fog
- *
- * INPUT
- *
- * Old - fog to copy
- *
- * OUTPUT
- *
- * RETURNS
- *
- * FOG * - new fog
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Copy a fog.
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- void *Copy_Fog(Old)
- FOG *Old;
- {
- FOG *New;
-
- New = Create_Fog();
-
- *New = *Old;
-
- New->Turb = (TURB *)Copy_Warps(((WARP *)Old->Turb));
-
- return (New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Destroy_Fog
- *
- * INPUT
- *
- * Fog - fog to destroy
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Destroy a fog.
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- void Destroy_Fog(Fog)
- FOG *Fog;
- {
- if (Fog != NULL)
- {
- Destroy_Turb(Fog->Turb);
-
- POV_FREE(Fog);
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Create_Rainbow
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * RAINBOW * - created rainbow
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Create a rainbow.
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- RAINBOW *Create_Rainbow()
- {
- RAINBOW *New;
-
- New = (RAINBOW *)POV_MALLOC(sizeof(RAINBOW), "fog");
-
- New->Distance = Max_Distance;
- New->Jitter = 0.0;
- New->Angle = 0.0;
- New->Width = 0.0;
-
- New->Falloff_Width = 0.0;
- New->Arc_Angle = 180.0;
- New->Falloff_Angle = 180.0;
-
- New->Pigment = NULL;
-
- Make_Vector(New->Antisolar_Vector, 0.0, 0.0, 0.0);
-
- Make_Vector(New->Right_Vector, 1.0, 0.0, 0.0);
- Make_Vector(New->Up_Vector, 0.0, 1.0, 0.0);
-
- New->Next = NULL;
-
- return (New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Copy_Rainbow
- *
- * INPUT
- *
- * Old - rainbow to copy
- *
- * OUTPUT
- *
- * RETURNS
- *
- * RAINBOW * - new rainbow
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Copy a rainbow.
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- void *Copy_Rainbow(Old)
- RAINBOW *Old;
- {
- RAINBOW *New;
-
- New = Create_Rainbow();
-
- *New = *Old;
-
- return (New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Destroy_Rainbow
- *
- * INPUT
- *
- * Rainbow - rainbow to destroy
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Destroy a rainbow.
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- void Destroy_Rainbow(Rainbow)
- RAINBOW *Rainbow;
- {
- if (Rainbow != NULL)
- {
- Destroy_Pigment(Rainbow->Pigment);
-
- POV_FREE(Rainbow);
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Create_Skysphere
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * SKYSPHERE * - created skysphere
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Create a skysphere.
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- SKYSPHERE *Create_Skysphere()
- {
- SKYSPHERE *New;
-
- New = (SKYSPHERE *)POV_MALLOC(sizeof(SKYSPHERE), "fog");
-
- New->Count = 0;
-
- New->Pigments = NULL;
-
- New->Trans = Create_Transform();
-
- return (New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Copy_Skysphere
- *
- * INPUT
- *
- * Old - skysphere to copy
- *
- * OUTPUT
- *
- * RETURNS
- *
- * SKYSPHERE * - copied skysphere
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Copy a skysphere.
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- void *Copy_Skysphere(Old)
- SKYSPHERE *Old;
- {
- int i;
- SKYSPHERE *New;
-
- New = Create_Skysphere();
-
- Destroy_Transform(New->Trans);
-
- *New = *Old;
-
- New->Trans = Copy_Transform(Old->Trans);
-
- if (New->Count > 0)
- {
- New->Pigments = (PIGMENT **)POV_MALLOC(New->Count*sizeof(PIGMENT *), "skysphere pigment");
-
- for (i = 0; i < New->Count; i++)
- {
- New->Pigments[i] = Copy_Pigment(Old->Pigments[i]);
- }
- }
-
- return (New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Destroy_Skysphere
- *
- * INPUT
- *
- * Skysphere - skysphere to destroy
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Destroy a skysphere.
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- void Destroy_Skysphere(Skysphere)
- SKYSPHERE *Skysphere;
- {
- int i;
-
- if (Skysphere != NULL)
- {
- for (i = 0; i < Skysphere->Count; i++)
- {
- Destroy_Pigment(Skysphere->Pigments[i]);
- }
-
- POV_FREE(Skysphere->Pigments);
-
- Destroy_Transform(Skysphere->Trans);
-
- POV_FREE(Skysphere);
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Rotate_Skysphere
- *
- * INPUT
- *
- * Vector - Rotation vector
- *
- * OUTPUT
- *
- * Skysphere - Pointer to skysphere structure
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Rotate a skysphere.
- *
- * CHANGES
- *
- * Feb 1996 : Creation.
- *
- ******************************************************************************/
-
- void Rotate_Skysphere(Skysphere, Vector)
- SKYSPHERE *Skysphere;
- VECTOR Vector;
- {
- TRANSFORM Trans;
-
- Compute_Rotation_Transform(&Trans, Vector);
-
- Transform_Skysphere(Skysphere, &Trans);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Scale_Skysphere
- *
- * INPUT
- *
- * Vector - Scaling vector
- *
- * OUTPUT
- *
- * Skysphere - Pointer to skysphere structure
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Scale a skysphere.
- *
- * CHANGES
- *
- * Feb 1996 : Creation.
- *
- ******************************************************************************/
-
- void Scale_Skysphere(Skysphere, Vector)
- SKYSPHERE *Skysphere;
- VECTOR Vector;
- {
- TRANSFORM Trans;
-
- Compute_Scaling_Transform(&Trans, Vector);
-
- Transform_Skysphere(Skysphere, &Trans);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Translate_Skysphere
- *
- * INPUT
- *
- * Vector - Translation vector
- *
- * OUTPUT
- *
- * Skysphere - Pointer to skysphere structure
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Translate a skysphere.
- *
- * CHANGES
- *
- * Feb 1996 : Creation.
- *
- ******************************************************************************/
-
- void Translate_Skysphere(Skysphere, Vector)
- SKYSPHERE *Skysphere;
- VECTOR Vector;
- {
- TRANSFORM Trans;
-
- Compute_Translation_Transform(&Trans, Vector);
-
- Transform_Skysphere(Skysphere, &Trans);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Transform_Skysphere
- *
- * INPUT
- *
- * Trans - Pointer to transformation
- *
- * OUTPUT
- *
- * Skysphere - Pointer to skysphere structure
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Transform a skysphere.
- *
- * CHANGES
- *
- * Feb 1996 : Creation.
- *
- ******************************************************************************/
-
- void Transform_Skysphere(Skysphere, Trans)
- SKYSPHERE *Skysphere;
- TRANSFORM *Trans;
- {
- if (Skysphere->Trans == NULL)
- {
- Skysphere->Trans = Create_Transform();
- }
-
- Compose_Transforms(Skysphere->Trans, Trans);
- }
-
-
-
-